package com.java.practise.tags;

import java.sql.ResultSetMetaData;
import java.sql.SQLException;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;

@SuppressWarnings("serial")
public class Paginated extends Base {
	protected static int FIRST_BLOCK_THRESHOLD 			= 5;
	protected static int LAST_BLOCK_THRESHOLD 			= 0;
	protected static int DEFAULT_PAGE_LIMIT 			= 10;
	
	protected int currentPage 							= 1;
	protected int rowsPerPage 							= 10;
	protected String uri 								= "";
	protected String queryString 						= "";
	protected int count;
	
	public void setCurrentPage(int currentPage) {
		if(currentPage > 0) {
			this.currentPage = currentPage;
		}
	}

	public void setRowsPerPage(int rowsPerPage) {
		this.rowsPerPage = rowsPerPage;
	}
	
	public void setUri(String uri) {
		this.uri = uri;
	}

	public void setQueryString(String queryString) {
		if(queryString != null && queryString.length() > 0) {
			int endIndex = queryString.indexOf(BREAD_CRUMB_LITERAL);
			if(endIndex >= 0) {
				this.queryString = queryString.substring(0, endIndex);
			}
			else {
				endIndex = queryString.indexOf(BREAD_CRUMB_LITERAL_2);
				if(endIndex >= 0) {
					this.queryString = queryString.substring(0, endIndex);
				}
				else {
					this.queryString = queryString;
				}
			}
		}
		else {
			this.queryString = "";
		}
	}
	
	private String getUrlForBreadCrumbs() {
		String url = "";
		if(uri.length() > 0) {
			url = url + uri;	
		}
		if(queryString.length() > 0) {
			url = url + "?" + queryString + "&p=";
		}
		else {
			url = url + "?p=";
		}
		return url;
	}

	public int doEndTag() throws JspException {
		try {
			JspWriter out = pageContext.getOut();
			out.print(this.paginatedTable());
		}
		catch(Exception ex) {
			throw new JspException("Exception occured: " + ex.getMessage());
		}
		return EVAL_PAGE;
	}
	
	protected StringBuffer paginatedTable() throws SQLException{
		StringBuffer stringBuffer = new StringBuffer();
		ResultSetMetaData rsmd = rst.getMetaData();
		try {
			int z = 1;
			int totalNoOfRows = this.getRowCount(rst);
			int totalNoOfPages = totalNoOfRows / rowsPerPage ;
			int absoluteRowPosition = (rowsPerPage * (currentPage - 1));
			if(absoluteRowPosition > 0) {
				rst.absolute(absoluteRowPosition);
			}
			if(totalNoOfRows%rowsPerPage > 0) {
				totalNoOfPages++;
			}
			count = rsmd.getColumnCount(); 
		    stringBuffer.append("<tr>"); 
    		if(select) {
    			stringBuffer.append("<td valign='top' align='center' style='" + this.defaultHeaderCssStyle() + "' class='" + this.headerStyle + "'>Select</td>");
    		}
		    for (int i = 1; i <= count; i++) {
	    		stringBuffer.append("<td id='" + i + "' style='" + this.defaultHeaderCssStyle() + "' class='" + this.headerStyle + "' ondblclick='toggleWrap(this.id, " + totalNoOfRows + ")' nowrap='nowrap'>");
		    	stringBuffer.append(rsmd.getColumnName(i) + " [" + rsmd.getColumnTypeName(i).toLowerCase() + "]");
		    	stringBuffer.append("</td>");
		   	}		
	    	stringBuffer.append("</tr>");   
	    	
		    while(rst.next()) {
		    	if(z > rowsPerPage) {
		    		break;
		    	}
		    	stringBuffer.append("<tr valign='top' name='checkBox" + z + "' onmouseover='focusRow(this)' onmouseout='defocusRow(this)'>");
		    	/* 
		    	 * If we are seeing the content of the table.
		    	 * We need to have a select box.
		    	 */
		    	if(select) {
			    	stringBuffer.append("<td valign='top' style='" + this.defaultRowCssStyle() + "' class='" + this.rowStyle + "' align='center' width='20px'>");
			    	stringBuffer.append("<input type='checkbox' id='selectedRow' name='selectedRow' value=" + rst.getString(1) + ">");
			    	stringBuffer.append("</td>");
		    	}
		    	
		    	/*
		    	 * Code for printing the Column Values
		    	 */
		    	for (int i = 1; i <= count; i++) {
			    	stringBuffer.append("<td id='column" + z + i + "' style='" + this.defaultRowCssStyle() + "' class='" + this.rowStyle + "' ondblclick='toggleWrap(" + i + " , " + totalNoOfRows + ")' nowrap='nowrap' >");
			    	if(rsmd.getColumnTypeName(i) == "DATE" || rsmd.getColumnTypeName(i) == "DATETIME")
			    		stringBuffer.append(rst.getInt(i));
			    	else{
			    		String data = rst.getString(i);
			    		if(data != null && data.startsWith("<")){
			    			stringBuffer.append(this.parseXMLString(data));
			    		}
			    		else{
			    			stringBuffer.append(data);
			    		}		    	
			    	}
		        	stringBuffer.append("</td>");
			   	}		
		    	stringBuffer.append("</tr>");
		    	z++;
		    }
		    /*
		     * This will display a message when the table is without any rows.
		     */
		    if(!rst.first()) {
		    	stringBuffer.append("<tr>");
		    	stringBuffer.append("<td colspan=" + (count + 1) + " style='" + this.defaultRowCssStyle() + "' class='" + this.rowStyle + "'><span style='color:red;'>The table is empty.</span></td>");
		    	stringBuffer.append("</tr>");
		    }
	    	
		    /*
		     * To display pagination
		     */
		    stringBuffer.append(showPagination(totalNoOfPages));

		    /*
		     * To get the number of rows count.
		     */
		    if(rowCountRequired) {
		    	stringBuffer.append("<tr>");
		    	stringBuffer.append("<td style='" + this.defaultFooterCssStyle() + "' class='" + this.footerStyle + "' colspan='" + (count + 1) + "'>");
		    	stringBuffer.append("Total Row Count: " + totalNoOfRows);
		    	stringBuffer.append("&nbsp;&nbsp;&nbsp;");
		    	stringBuffer.append("Page Row Count: " + (z - 1));
		    	stringBuffer.append("</td>");
		    	stringBuffer.append("</tr>");
		    }
		} catch (SQLException ex) {
			throw new SQLException("SQLException occured while forming the paginated table: " + ex.getMessage());
		}

		return stringBuffer;
	}

	protected StringBuffer showPagination(int totalNoOfPages) {
		StringBuffer paginationBuffer = new StringBuffer();
	    int cp = currentPage;
	    boolean splitPagination = false;
	    
    	if(totalNoOfPages > 1) {
    		paginationBuffer.append("<tr>");
    		paginationBuffer.append("<td style='" + this.defaultRowCssStyle() + "' class='" + this.rowStyle + "' colspan='" + (count + 1) + "'>");
    		paginationBuffer.append("Pages: ");
    		if(cp > 1) {
    			paginationBuffer.append("&nbsp;<a style='" + this.defaultLinkStyle() + "' href='" + getUrlForBreadCrumbs() + "1'>&lt;&lt;</a>&nbsp;|");
    			paginationBuffer.append("&nbsp;<a style='" + this.defaultLinkStyle() + "' href='" + getUrlForBreadCrumbs() + (cp - 1) + "'>&lt;</a>&nbsp;|&nbsp;");
    		}
    		else {
    			paginationBuffer.append("&nbsp;&lt;&lt;&nbsp;|");
    			paginationBuffer.append("&nbsp;&lt;&nbsp;|&nbsp;");
    		}
    	}
    	
	    if(totalNoOfPages <= DEFAULT_PAGE_LIMIT) {
	    	if(totalNoOfPages > 1) {
	    		loopForPageNumbers(1, totalNoOfPages, cp, paginationBuffer);
	    	}
	    }
	    else {
	    	LAST_BLOCK_THRESHOLD = totalNoOfPages - (FIRST_BLOCK_THRESHOLD - 2);
	    	if(cp > FIRST_BLOCK_THRESHOLD - 1 && cp < LAST_BLOCK_THRESHOLD) {
	    		splitPagination = true;
	    	}
	    	
	    	if(splitPagination) {
	    		loopForPageNumbers(1, FIRST_BLOCK_THRESHOLD - 3, cp, paginationBuffer);
	    		paginationBuffer.append(".&nbsp;.&nbsp;.&nbsp;&nbsp;");
	    		loopForPageNumbers((cp - 2), (cp + 2), cp, paginationBuffer);
	        	paginationBuffer.append(".&nbsp;.&nbsp;.&nbsp;&nbsp;");
	        	loopForPageNumbers(LAST_BLOCK_THRESHOLD + 2, totalNoOfPages, cp, paginationBuffer);
	    	}
	    	else {
	    		loopForPageNumbers(1, FIRST_BLOCK_THRESHOLD, cp, paginationBuffer);
	    		paginationBuffer.append(".&nbsp;.&nbsp;.&nbsp;.&nbsp;.&nbsp;&nbsp;");
	    		loopForPageNumbers(LAST_BLOCK_THRESHOLD - 1, totalNoOfPages, cp, paginationBuffer);
	    	}
	    }
	    
	    if(totalNoOfPages > 1) {
	    	if(cp < totalNoOfPages) {
	    		paginationBuffer.append("|&nbsp;<a style='" + this.defaultLinkStyle() + "' href='" + getUrlForBreadCrumbs() + (cp + 1) +"'>&gt;</a>&nbsp;|");
	    		paginationBuffer.append("&nbsp;<a style='" + this.defaultLinkStyle() + "' href='" + getUrlForBreadCrumbs() + totalNoOfPages + "'>&gt;&gt;</a>&nbsp;");
	    	}
	    	else {
	    		paginationBuffer.append("|&nbsp;>&nbsp;|");
	    		paginationBuffer.append("&nbsp;>>&nbsp;");
	    	}
	    	paginationBuffer.append("</td>");
	    	paginationBuffer.append("</tr>");
	    }
	    return paginationBuffer;
	}

	protected void loopForPageNumbers(int begin, int end, int cp, StringBuffer stringBuffer) {
    	for(int index = begin; index <= end; index++) {
    		String currentPageMarkup = "";
    		if(index == cp) {
    			currentPageMarkup = this.pageMarkupStyle;
    		}
    		String href = "<a href='" + getUrlForBreadCrumbs() + index + "' class='" + currentPageMarkup + "'>" + index + "</a>";
    		stringBuffer.append(href + "&nbsp;&nbsp;");
    	}
	}
}
